﻿// ## 2023/09/07 # 黑店小小二 # 还原部队任务时判断对之前任务状态判断 ##
// ## 2023/05/09 # 铃 # 缩减探测距离到2 ##
// ## 2023/03/19 # 铃 # 创建,目的是为了让AI在野战中优先攻击府##

namespace AI部队优先目标优化
{
    const int 部队目标变更_势力条件 = 0;          // 0:电脑AI和player _委任军团，1:player _委任军团，2:电脑AI, 3:均未使用  0:
    const bool 部队目标变更_适用玩家军团 = false; // 与势力条件无关，设定是否适用，忽略玩家的任务指定，建议false
    const int 探测距离 = 4;
    const int 调整最大部队数 = 5;
    bool 调试模式 = false;

    //=======================================================================================

    class Main
    {
        array<int> attack_building_unit_num(ch::get_spec_end(), 0);

        Main()
        {
//            pk::bind(111, pk::trigger111_t(onTurnStart));
//            pk::bind(164, pk::trigger164_t(onkillbuilding));
        }
        //---------------------------------------------------------------------------

        //---------------------------------------------------------------------------

        void onTurnStart(pk::force @force)
        {

            array<int> _attack_building_unit_num(ch::get_spec_end(), 0);
            attack_building_unit_num = _attack_building_unit_num;
            if (pk::is_campaign())
                return;

            if (!pk::is_normal_force(force))
                return;
            int force_id = pk::get_current_turn_force_id();
            if (!pk::is_normal_force(force_id))
                return;

            // 本势力全体部队
            pk::array<pk::unit @> arr_unit_list = pk::list_to_array(pk::get_unit_list(force));
            if (int(arr_unit_list.length) == 0)
                return;


            for (int i = 0; i < int(arr_unit_list.length); i++)
            {
                pk::unit @unit = arr_unit_list[i];

                if (pk::is_alive(unit) and !pk::is_player_controlled(unit) and unit.type == 部队类型_战斗 and unit.order != 部队任务_撤退)
                {
                        optimize_target(unit); // 部队目标重新设置函数
                }
            }
        }

        //---------------------------------------------------------------------------
        //                          部队目标重新设置函数
        //---------------------------------------------------------------------------
        void optimize_target(pk::unit @unit)
        {

            //                if(force_id == 34){
//                    ch::debug(2,pk::format("onTurnStart,force_id:{},arr_unit_list:{}",force_id,arr_unit_list.length));
//                    ch::debug(2,pk::format("is_player_controlled,{},unit.type:{}", pk::is_player_controlled(unit),unit.type));
//                }

            int force_id = unit.get_force_id();
            pk::force @force = pk::get_force(force_id);

            if (!pk::is_alive(unit) or unit.type != 部队类型_战斗 or unit.order == 部队任务_撤退)
                return;

            if (unit.weapon == 兵器_战马 or unit.weapon == 兵器_弩 or unit.weapon == 兵器_走舸 or unit.weapon == 兵器_斗舰 or unit.weapon == 兵器_楼船)
                return;

            pk::list<pk::building @> target_list = get_target_list(unit);

            // 如果列表为空就跳过
            if (target_list.count == 0)
                return;

            auto unit_p = ch::get_unit_p(unit.get_id());

            int spec_id = ch::get_spec_id(target_list[0]);

            array<pk::unit @> building_unit_list = get_building_unit_list(target_list[0], force_id);

            int 调整部队数;

            if (building_unit_list.length == 0)
                调整部队数 = 调整最大部队数;
            else if (building_unit_list.length > 0 and building_unit_list.length <= 2)
                调整部队数 = 0; // 此时先击溃部队
            else if (building_unit_list.length <= 5)
                调整部队数 = building_unit_list.length;
            else
                调整部队数 = 4;

            if (ch::is_valid_spec_id(spec_id) and attack_building_unit_num[spec_id] > 调整部队数)
                return;


            // // 防止重复设置，去除改设定
            // if (unit_p.setting)
            //     return;

            //对于没有耐久进攻力的部队,不需要进行操作
            if ((unit.weapon == 兵器_战马 or unit.weapon == 兵器_弩 or unit.weapon == 兵器_井阑 or unit.weapon == 兵器_走舸 or unit.weapon == 兵器_斗舰 or unit.weapon == 兵器_楼船) and ch::get_spec_p(spec_id).troops == 0)
                return;

                // 存储部队原始任务
            unit_p.set_ssunit_data(unit);


            // 重新设置攻击任务
            if (pk::is_enemy(unit, target_list[0]) and (unit.order == 部队任务_征服 or unit.order == 部队任务_拦截))
            {
                pk::set_order(unit, 部队任务_攻击, target_list[0].get_pos());
                pk::trace(pk::format("{}就近攻击府,部队任务被修改为攻击{},{}", pk::decode(pk::get_name(unit)), target_list[0].get_pos().x, target_list[0].get_pos().y));
            }


            if (ch::is_valid_spec_id(spec_id))
                attack_building_unit_num[spec_id] += 1;

            // 显示部队任务变更对话框
            if (pk::is_in_screen(target_list[0].get_pos()))
            {
                say_change_target_unit(unit, target_list[0]);

            }
        }


        //---------------------------------------------------------------------------
        // 获取列表
        pk::list<pk::building @> get_target_list(pk::unit @unit)
        {
            pk::list<pk::building @> target_list;

            pk::array<pk::point> range = pk::range(unit.pos, 1, 探测距离 + get_max_atk_range(unit));

            for (int i = 0; i < int(range.length); i++)
            {
                if (!pk::is_valid_pos(range[i]))
                    continue;

                pk::building @target_building = pk::get_building(range[i]);

                if (target_building is null)
                    continue;

                if (!pk::is_alive(target_building))
                    continue;

                int building_id = target_building.get_id();

                // //如果在探测范围内发现了建筑,则跳出判决
                // if (building_id >= 0 and building_id < 据点_末)
                // {
                //     target_list.clear();
                //     break;
                // }
                // 列表已经有就跳过
                if (target_list.contains(target_building))
                    continue;

                // 如果是空建筑就跳过
                if (pk::get_building(range[i]).get_force_id() == -1)
                    continue;

                // 不是敌对跳过
                if (!pk::is_enemy(unit, target_building))
                    continue;


                // 如果不是府就跳过
                if (ch::to_spec_id(building_id) == -1)
                    continue;


                //不考虑异族封地
                if (ch::to_spec_id(building_id) >= ch::get_normal_spec_end())
                    continue;


                    // 不在移动范围就跳过
                    // if (!check_base_in_movable_range(unit, target_building))
                    //  continue;

                target_list.add(target_building);
            }

            return target_list;
        }
        void onkillbuilding(int force_id, int facility_id, const pk::point& in pos, int a)
        {
            pk::force @force = pk::get_force(force_id);
            if (!pk::is_alive(force) or !pk::is_normal_force(force_id))
                return;
            if (force_id == -1)
                return;
            pk::list<pk::unit @> unit_list = pk::get_unit_list(force);
            if (unit_list.count > 0)
            {
                for (int i = 0; i < unit_list.count; i += 1)
                {
                    pk::unit @unit = unit_list[i];
                    auto unit_p = ch::get_unit_p(unit.get_id());

                   // pk::trace(pk::format("1{}部队 ", pk::decode(pk::get_name(unit))));
                    if (!pk::is_valid_pos(pos))return;
                    pk::hex @hex = pk::get_hex(pos);
                    if (!hex.has_building)return;

                    pk::building @building = pk::get_building(pos);
                    if (building is null) return;
                    int building_id = pk::get_building(pos).get_id();

                    if (!unit_p.setting)
                        continue;
                   // pk::trace(pk::format("2{}部队,building.get_id{},部队存储的任务{},部队当前任务{} ", pk::decode(pk::get_name(unit)), building_id, ss_unit.target, unit.target));
                    if (building_id == unit.target or unit.target == -1)
                    {
                        auto scenario_ai_table_unit = pk::get_scenario().ai_table.unit[unit.get_id()];
                        //pk::trace(pk::format("3{}部队,出征类型{},目标{} ", pk::decode(pk::get_name(unit)), scenario_ai_table_unit.deploy_type, scenario_ai_table_unit.deploy_target));
                        unit.target_type = unit_p.target_type;
                        // if (unit.target_type == 部队任务对象_部队)
                        //     pk::set_order(unit, unit.order, pk::get_unit(ss_unit.target).pos);


                        //部队的变化太大(可能走远了),如果部队已经不在了,又要犯傻撤退,倒不如直接重设更好
                        if (unit.target_type == 部队任务对象_据点 and pk::is_alive(pk::get_building(unit_p.target)) and pk::get_building(unit_p.target) !is null)
                            pk::set_order(unit, unit.order, pk::get_building(unit_p.target).pos);

                        //设为待命,然后走266重设
                        else pk::set_order(unit, 部队任务_待命, pk::point(-1, -1));


                    }


                }
            }
        }



//---------------------------------------------------------------------------

        void say_change_target_unit(pk::unit @unit, pk::building @building)
        {
            pk::person @leader = pk::get_person(unit.leader);

            string target_name = ch::get_spec_name(ch::to_spec_id(building.get_id()));

            pk::say(pk::encode(pk::format("大家跟我去占领\x1b[2x{}\x1b[0x!", target_name)), leader);
        }

        // 检查目标据点是否在部队的移动范围内
        bool check_base_in_movable_range(pk::unit @unit, pk::building @building)
        {
            if (!pk::is_alive(unit) or !pk::is_alive(building))
                return false;

            pk::array<pk::point> arr_range = pk::get_movable_pos(unit);

            for (int i = 0; i < int(arr_range.length); i++)
            {
                if (building.pos == arr_range[i])
                    return true;
            }
            return false;
        }


        // 部队攻击最大射程函数
        int get_max_atk_range(pk::unit @unit)
        {
            if (!pk::is_alive(unit))
                return 1;

            int weapon_id = unit.weapon;
            int max_range = 0;

            if (weapon_id == 兵器_弩)
                max_range = (unit.has_tech(技巧_强弩)) ? 3 : 2;
            else if (weapon_id == 兵器_战马)
                max_range = (unit.has_tech(技巧_骑射) or unit.has_skill(特技_白马)) ? 2 : 1;
            else if (weapon_id == 兵器_井阑)
                max_range = ((unit.has_skill(特技_射程)) ? 1 : 0) + (pk::get_tactics(战法_攻城火矢).max_range);
            else if (weapon_id == 兵器_投石)
                max_range = ((unit.has_skill(特技_射程)) ? 1 : 0) + (pk::get_tactics(战法_攻城投石).max_range);
            else if (weapon_id >= 兵器_走舸)
                max_range = 2;
            else
                max_range = 1;

            return max_range;
        }

        array<pk::unit @> get_building_unit_list(pk::building @building, int force_id)
        {
            array<pk::unit @> unit_list;
            pk::array<pk::point> range = pk::range(building.pos, 1, 2);
            for (int i = 0; i < int(range.length); i++)
            {
                if (!pk::is_valid_pos(range[i]))
                    continue;
                pk::unit @unit = pk::get_unit(range[i]);

                if (unit is null)
                    continue;

                //骑兵不需要攻击府
                if (unit.weapon == 兵器_战马 or unit.weapon == 兵器_弩)
                    continue;

                if (unit.get_force_id() != force_id and pk::is_enemy(unit, pk::get_force(force_id)))
                {
                    unit_list.insertLast(unit);
                }
            }
            return unit_list;
        }

                // 寻找撤退据点
        int loc_id;
        int service_id;
        pk::building @find_withdraw_base(pk::unit @unit)
        {
            array<pk::building @> dst_base_arr;

            main.loc_id = pk::get_building_id(unit.pos);
            if (main.loc_id < 0 or main.loc_id >= 据点_末)
                return null;
            main.service_id = pk::get_service(unit);

            for (int i = 0; i < 据点_末; i++)
            {
                pk::building @dst_base = pk::get_building(i);

                if (!pk::is_alive(dst_base))
                    continue;

                //太远不行
                if (unit_distance[loc_id][i] > 8)
                    continue;


                if (unit.is_player())
                {
                    pk::district @district = pk::get_district(pk::get_building(i).get_district_id());
                    if (district.no == 1)continue;
                }

                    //判断势力
                if (dst_base.get_force_id() != unit.get_force_id())
                    continue;

                dst_base_arr.insertLast(dst_base);
            }
            if (dst_base_arr.length == 0)return null;
            dst_base_arr.sort(function(a, b) {
                return unit_distance[main.loc_id][a.get_id()] - ((a.get_id() == main.service_id) ? 2 : 0) < unit_distance[main.loc_id][b.get_id()] - ((b.get_id() == main.service_id) ? 2 : 0);
            });

            if (dst_base_arr.length <= 0)
                return pk::get_building(pk::get_service(unit));
            else return  dst_base_arr[0];
        }
    }

    Main main;
}
